package br.mikhas.container.annotation;

import java.lang.annotation.Annotation;

import br.mikhas.container.config.BeanDefinition;
import br.mikhas.container.factory.BeanPostProcessor;
import br.mikhas.util.Assert;

/**
 * Defines a scanned annotation and the operations which should be executed on
 * post-process phase.
 * 
 * @author Mikhail Domanoski
 * 
 */
public abstract class AnnotationPostProcessor<T extends Annotation> implements
		BeanPostProcessor {

	/**
	 * The annotation class which will be used as stereotype
	 */
	protected Class<T> annotationClass;

	/**
	 * Creates a new {@link AnnotationPostProcessor} and defines which
	 * annotation will be scaned and post-processed.
	 * 
	 * @param annotationClass
	 *            The annotation to be processed
	 */
	public AnnotationPostProcessor(Class<T> annotationClass) {
		Assert.notNull(annotationClass);
		this.annotationClass = annotationClass;
	}

	/**
	 * Gets the processed annotation.
	 * 
	 * @return
	 */
	public Class<? extends Annotation> getResourceAnnotation() {
		return annotationClass;
	}

	/**
	 * It process the resource which are annotated with teh providen annotation
	 */
	@Override
	public final boolean mayProcess(BeanDefinition definition) {
		try {
			return definition.getInstantiatingClass().isAnnotationPresent(
					getResourceAnnotation());
		} catch (Throwable t) {
			return false;
		}
	}

	@Override
	public final Object processBean(BeanDefinition definition, Object resource) {
		T annotation = definition.getInstantiatingClass().getAnnotation(
				this.annotationClass);
		return processBean(definition, resource, annotation);
	}

	/**
	 * Executes post-process opeerations after bean has been initialized
	 * 
	 * @param definition
	 *            The bean definition
	 * @param resource
	 *            The current resource instance
	 * @param annotation
	 *            The annotation being processed
	 * @return The processed bean instance
	 */
	public abstract Object processBean(BeanDefinition definition,
			Object resource, T annotation);
}
